package com.ruoyi.project.fusion.algorithms;

import com.ruoyi.project.fusion.domain.BusinessStatusAggInfo;
import com.ruoyi.project.fusion.domain.BusinessStatusScores;
import com.ruoyi.project.fusion.utils.ComputeUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class BusinessStatusAlgorithm {
    public List<BusinessStatusScores> compute(List<BusinessStatusAggInfo> businessStatusAggInfos) {
        // 按照 chainType、scenario、product 分组
        Map<List<String>, List<BusinessStatusAggInfo>> groupedInfos = businessStatusAggInfos.stream()
                .collect(Collectors.groupingBy(info -> Arrays.asList(
                        info.getChainType(),
                        info.getScenario(),
                        info.getProduct(),
                        info.getEvent()
                )));

        List<BusinessStatusScores> scoresList = new ArrayList<>();

        for (Map.Entry<List<String>, List<BusinessStatusAggInfo>> entry : groupedInfos.entrySet()) {
            List<BusinessStatusAggInfo> group = entry.getValue();

            // 归一化数据
            List<Double> normalizedRevenueValues = normalizeValues(group.stream().map(BusinessStatusAggInfo::getTotalAnnualRevenue).collect(Collectors.toList()));
            List<Double> normalizedProfitValues = normalizeValues(group.stream().map(BusinessStatusAggInfo::getTotalAnnualProfit).collect(Collectors.toList()));
            List<Double> normalizedCostValues = normalizeValues(group.stream().map(BusinessStatusAggInfo::getTotalAnnualCost).collect(Collectors.toList()));
            List<Double> normalizedDebtRatioValues = normalizeValues(group.stream().map(BusinessStatusAggInfo::getAvgDebtRatio).collect(Collectors.toList()));
            List<Double> normalizedPaymentPeriodValues = normalizeValues(group.stream().map(BusinessStatusAggInfo::getAvgPaymentPeriod).collect(Collectors.toList()));

            // 计算各项指标的标准差
            double stdDevRevenue = ComputeUtils.calculateStandardDeviation(normalizedRevenueValues);
            double stdDevProfit = ComputeUtils.calculateStandardDeviation(normalizedProfitValues);
            double stdDevCost = ComputeUtils.calculateStandardDeviation(normalizedCostValues);
            double stdDevDebtRatio = ComputeUtils.calculateStandardDeviation(normalizedDebtRatioValues);
            double stdDevPaymentPeriod = ComputeUtils.calculateStandardDeviation(normalizedPaymentPeriodValues);

            // 计算总标准差
            double totalStdDev = stdDevRevenue + stdDevProfit + stdDevCost + stdDevDebtRatio + stdDevPaymentPeriod;

            // 计算权重
            double weightRevenue = (totalStdDev == 0) ? 0.25 : stdDevRevenue / totalStdDev;
            double weightProfit = (totalStdDev == 0) ? 0.25 : stdDevProfit / totalStdDev;
            double weightCost = (totalStdDev == 0) ? 0.25 : stdDevCost / totalStdDev;
            double weightDebtRatio = (totalStdDev == 0) ? 0.25 : stdDevDebtRatio / totalStdDev;
            double weightPaymentPeriod = (totalStdDev == 0) ? 0.25 : stdDevPaymentPeriod / totalStdDev;

            // 计算分数
            for (int i = 0; i < group.size(); i++) {
                BusinessStatusAggInfo info = group.get(i);

                double score = (normalizedRevenueValues.get(i) * weightRevenue) +
                        (normalizedProfitValues.get(i) * weightProfit) +
                        (normalizedCostValues.get(i) * weightCost) +
                        (normalizedDebtRatioValues.get(i) * weightDebtRatio) +
                        (normalizedPaymentPeriodValues.get(i) * weightPaymentPeriod);

                BusinessStatusScores businessStatusScore = new BusinessStatusScores();
                businessStatusScore.setChainType(info.getChainType());
                businessStatusScore.setEnterpriseName(info.getEnterpriseName());
                businessStatusScore.setScenario(info.getScenario());
                businessStatusScore.setProduct(info.getProduct());
                businessStatusScore.setEvent(info.getEvent());
                businessStatusScore.setScore(ComputeUtils.roundToTwoDecimalPlaces((float) score));

                scoresList.add(businessStatusScore);
            }
        }

        return scoresList;
    }

    private List<Double> normalizeValues(List<Double> values) {
        double min = values.stream().min(Double::compare).orElse(0.0);
        double max = values.stream().max(Double::compare).orElse(1.0);
        return values.stream()
                .map(value -> (max == min) ? 0.5 : (value - min) / (max - min))
                .collect(Collectors.toList());
    }
}
